
#include <BFile>

#include "OscDocument.h"

OscDocument::OscDocument()
{
	if (_readFuncMap.empty())
	{
		_readFuncMap["scene"]		= (readFunc)&OscDocument::readScene;
		_readFuncMap["group"]		= (readFunc)&OscDocument::readGroup;
		_readFuncMap["node"]		= (readFunc)&OscDocument::readNode;
		_readFuncMap["light"]		= (readFunc)&OscDocument::readLight;
		_readFuncMap["camera"]		= (readFunc)&OscDocument::readCamera;
		_readFuncMap["billboard"]	= (readFunc)&OscDocument::readBillboard;

		_readFuncMap["mesh"]		= (readFunc)&OscDocument::readMesh;
		_readFuncMap["geometry"]	= (readFunc)&OscDocument::readGeometry;
		_readFuncMap["textual"]		= (readFunc)&OscDocument::readTextual;
		_readFuncMap["particle"]	= (readFunc)&OscDocument::readParticle;
		_readFuncMap["element"]		= (readFunc)&OscDocument::readElement;

		_readFuncMap["cube"]		= (readFunc)&OscDocument::readCube;
		_readFuncMap["cone"]		= (readFunc)&OscDocument::readCone;
		_readFuncMap["cylinder"]	= (readFunc)&OscDocument::readCylinder;
		_readFuncMap["sphere"]		= (readFunc)&OscDocument::readSphere;
		_readFuncMap["geosphere"]	= (readFunc)&OscDocument::readGeoSphere;
		_readFuncMap["tube"]		= (readFunc)&OscDocument::readTube;
		_readFuncMap["torus"]		= (readFunc)&OscDocument::readTorus;
		_readFuncMap["surface"]		= (readFunc)&OscDocument::readSurface;
		_readFuncMap["terrain"]		= (readFunc)&OscDocument::readTerrain;

		_readFuncMap["material"]	= (readFunc)&OscDocument::readMaterial;
		_readFuncMap["image"]		= (readFunc)&OscDocument::readImage;
		_readFuncMap["pixmap"]		= (readFunc)&OscDocument::readPixmap;
		_readFuncMap["program"]		= (readFunc)&OscDocument::readProgram;
		_readFuncMap["shader"]		= (readFunc)&OscDocument::readShader;
		_readFuncMap["uniform"]		= (readFunc)&OscDocument::readUniform;
		_readFuncMap["script"]		= (readFunc)&OscDocument::readScript;
	}
	if (_writeFuncMap.empty())
	{
		_writeFuncMap["scene"]		= (writeFunc)&OscDocument::writeScene;
		_writeFuncMap["group"]		= (writeFunc)&OscDocument::writeGroup;
		_writeFuncMap["node"]		= (writeFunc)&OscDocument::writeNode;
		_writeFuncMap["light"]		= (writeFunc)&OscDocument::writeLight;
		_writeFuncMap["camera"]		= (writeFunc)&OscDocument::writeCamera;
		_writeFuncMap["billboard"]	= (writeFunc)&OscDocument::writeBillboard;

		_writeFuncMap["mesh"]		= (writeFunc)&OscDocument::writeMesh;
		_writeFuncMap["geometry"]	= (writeFunc)&OscDocument::writeGeometry;
		_writeFuncMap["textual"]	= (writeFunc)&OscDocument::writeTextual;
		_writeFuncMap["particle"]	= (writeFunc)&OscDocument::writeParticle;
		_writeFuncMap["element"]	= (writeFunc)&OscDocument::writeElement;

		_writeFuncMap["cube"]		= (writeFunc)&OscDocument::writeCube;
		_writeFuncMap["cone"]		= (writeFunc)&OscDocument::writeCone;
		_writeFuncMap["cylinder"]	= (writeFunc)&OscDocument::writeCylinder;
		_writeFuncMap["sphere"]		= (writeFunc)&OscDocument::writeSphere;
		_writeFuncMap["geosphere"]	= (writeFunc)&OscDocument::writeGeoSphere;
		_writeFuncMap["tube"]		= (writeFunc)&OscDocument::writeTube;
		_writeFuncMap["torus"]		= (writeFunc)&OscDocument::writeTorus;
		_writeFuncMap["surface"]	= (writeFunc)&OscDocument::writeSurface;
		_writeFuncMap["terrain"]	= (writeFunc)&OscDocument::writeTerrain;

		_writeFuncMap["material"]	= (writeFunc)&OscDocument::writeMaterial;
		_writeFuncMap["image"]		= (writeFunc)&OscDocument::writeImage;
		_writeFuncMap["pixmap"]		= (writeFunc)&OscDocument::writePixmap;
		_writeFuncMap["program"]	= (writeFunc)&OscDocument::writeProgram;
		_writeFuncMap["shader"]		= (writeFunc)&OscDocument::writeShader;
		_writeFuncMap["uniform"]	= (writeFunc)&OscDocument::writeUniform;
		_writeFuncMap["script"]		= (writeFunc)&OscDocument::writeScript;
	}
}
OscDocument::~OscDocument()
{

}

bool OscDocument::setFormat(const BString& format)
{
	return _sondoc.setFormat(format);
}
const BString& OscDocument::format() const
{
	return _sondoc.format();
}

BObject* OscDocument::load(const BString& fileName)
{
	BFile file(fileName);
	if (!file.open(IO_Read))
	{
		message() << "OSC Error : Read file failed : Can't open file " << fileName;
		return 0;
	}
	return read(file);
}
BObject* OscDocument::read(const BStream& stream)
{
	_readObjectMap.clear();
	_writeObjectMap.clear();

	stream.seek(0);
	BSonNodeHolder sonode = _sondoc.read(stream);
	if (sonode == 0)
		return 0;

	BObject* object = readObject(sonode);
	return object;
}

bool OscDocument::load(const BString& fileName, BObject* object)
{
	BFile file(fileName);
	if (!file.open(IO_ReadText))
	{
		message() << "OSC Error : Read file failed : Can't open file " << fileName;
		return false;
	}
	return read(file, object);
}
bool OscDocument::save(const BString& fileName, const BObject* object) const
{
	BFile file(fileName);
	if (!file.open(IO_WriteText))
	{
		message() << "OSC Error : Write file failed : Can't open file " << fileName;
		return false;
	}
	return write(file, object);
}

bool OscDocument::read(const BStream& stream, BObject* object)
{
	_readObjectMap.clear();
	_writeObjectMap.clear();

	stream.seek(0);

	BSonNode* sonode = _sondoc.read(stream);
	if (sonode == 0)
		return false;

	BString type = object->className();
	if (type.beginWith('B'))
		type.remove(0);
	type.lower();
	if (sonode->name() == type)
	{
		OscDocument::readFunc read = _readFuncMap[sonode->name()];
		if (!read)
		{
			message() << "OSC Error : Read object failed : No read func for " << type;
			return false;
		}
		if (false == (this->*read)(sonode, object))
		{
			message() << "OSC Error : Read object failed " << type;
			return false;
		}
		return true;
	}

	return false;
}
bool OscDocument::write(BStream& stream, const BObject* object) const
{
	if (!object)
		return false;

	_readObjectMap.clear();
	_writeObjectMap.clear();

	BHolder<BSonNode> sonode = writeObject(object);
	if (!sonode)
	{
		message() << "OSC Error : Write node failed : " << object->className();
		return false;
	}
	return _sondoc.write(stream, sonode);
}

BObject* OscDocument::readObject(const BSonNode* node)
{
	const BString& idStr = node->attrib("id");
	int id = idStr.toInt();
	if (id > 0)
	{
		auto it = _readObjectMap.find(id);
		if (it.valid())
		{
			return it.value();
		}
	}
	const BString& name = node->name();
	BObject* object = 0;
	if (name == "scene")
		object = new BScene();
	else if (name == "node")
		object = new BNode();
	else if (name == "light")
		object = new BLight();
	else if (name == "camera")
		object = new BCamera();
	else if (name == "group")
		object = new BGroup();
	else if (name == "mesh")
		object = new BMesh();
	else if (name == "geometry")
		object = new BGeometry();
	else if (name == "cone")
		object = new BCone();
	else if (name == "cube")
		object = new BCube();
	else if (name == "cylinder")
		object = new BCylinder();
	else if (name == "sphere")
		object = new BSphere();
	else if (name == "geosphere")
		object = new BGeoSphere();
	else if (name == "torus")
		object = new BTorus();
	else if (name == "tube")
		object = new BTube();
	else if (name == "surface")
		object = new BSurface();
	else if (name == "terrain")
		object = new BTerrain();
	else if (name == "billboard")
		object = new BBillboard();
	else if (name == "particle")
		object = new BParticle();
	else if (name == "style")
		object = new BStyle();
	else if (name == "image")
		object = new BImage();
	else if (name == "pixmap")
		object = new BPixmap();
	else if (name == "material")
		object = new BMaterial();
	else if (name == "script")
		object = new BScript();
	else
	{
		message() << "OSC Error : Create object failed :  " << name;
		return 0;
	}
	OscDocument::readFunc read = OscDocument::_readFuncMap[name];
	if (!read)
	{
		message() << "OSC Error : Read object failed : No read func for " << name;
		delete object;
		return 0;
	}
	if (false == (this->*read)(node, object))
	{
		message() << "OSC Error : Read object failed " << name;
		delete object;
		return 0;
	}
	if (id > 0)
	{
		_readObjectMap[id] = object;
	}
	return object;
}

bool OscDocument::readObjectData(const BSonNode* son, BObject* object)
{
	const BString& name = son->attrib("name");
	object->setName(name);
	const BString& enabledStr = son->attrib("enabled");
	if (enabledStr.size())
	{
		object->setEnabled(enabledStr == "true");
	}
	return true;
}
bool OscDocument::readShapeData(const BSonNode* son, BShape* shape)
{
	const BString& visibleStr = son->attrib("visible");
	if (visibleStr.size())
	{
		bool visible = visibleStr == "true";
		shape->setVisible(visible);
	}

	const BString& lightingStr = son->attrib("lighting");
	if (lightingStr.size())
	{
		bool lighting = lightingStr == "true";
		shape->setLighting(lighting);
	}

	const BString& cullbackStr = son->attrib("cullback");
	if (cullbackStr.size())
	{
		bool cullback = cullbackStr == "true";
		shape->setCullback(cullback);
	}

	const BString& depthTestStr = son->attrib("depthTest");
	if (depthTestStr.size())
	{
		bool depthTest = depthTestStr == "true";
		shape->setDepthTest(depthTest);
	}

	const BString& transparentStr = son->attrib("transparent");
	if (transparentStr.size())
	{
		bool transparent = transparentStr == "true";
		shape->setTransparent(transparent);
	}

	const BString& pointSmoothStr = son->attrib("pointSmooth");
	if (pointSmoothStr.size())
	{
		bool pointSmooth = pointSmoothStr == "true";
		shape->setPointSmooth(pointSmooth);
	}

	const BString& pointSizeStr = son->attrib("pointSize");
	if (pointSizeStr.size())
	{
		int pointSize = pointSizeStr.toInt();
		shape->setPointSize(pointSize);
	}

	const BString& lineSmoothStr = son->attrib("lineSmooth");
	if (lineSmoothStr.size())
	{
		bool lineSmooth = lineSmoothStr == "true";
		shape->setLineSmooth(lineSmooth);
	}

	const BString& lineWidthStr = son->attrib("lineWidth");
	if (lineWidthStr.size())
	{
		int lineWidth = lineWidthStr.toInt();
		shape->setLineWidth(lineWidth);
	}

	const BString& polygonSmoothStr = son->attrib("polygonSmooth");
	if (polygonSmoothStr.size())
	{
		bool polygonSmooth = polygonSmoothStr == "true";
		shape->setPolygonSmooth(polygonSmooth);
	}

	const BString& polygonModeStr = son->attrib("polyMode");
	if (polygonModeStr.size())
	{
		char polyMode = polygonModeStr.toInt();
		shape->setPolyMode((PolyMode)polyMode);
	}

	BMatrix matrix;
	{
		const BString& positionStr = son->attrib("position");
		if (positionStr.size())
		{
			BVector position = stringToVector(positionStr);
			matrix.setPosition(position);
		}

		const BString& rotationStr = son->attrib("rotation");
		if (rotationStr.size())
		{
			BQuater rotation = stringToQuater(rotationStr);
			matrix.setRotate(rotation);
		}

		const BString& scaleStr = son->attrib("scale");
		if (scaleStr.size())
		{
			BVector scale = stringToVector(scaleStr);
			matrix.setScale(scale);
		}
	}
	shape->setMatrix(matrix);

	const BString& colorStr = son->attrib("color");
	if (colorStr.size())
	{
		BColor color = stringToColor(colorStr);
		shape->setColor(color);
	}

	const BSonNode* materialNode = son->child("material");
	if (materialNode)
	{
		BMaterial* material = (BMaterial*)readObject(materialNode);
		shape->setMaterial(material);
	}

	const BSonNode* textureNode = son->child("image");
	if (textureNode)
	{
		BTexture* texture = (BTexture*)readObject(textureNode);
		shape->setTexture(texture);
	}

	const BSonNode* programNode = son->child("program");
	if (programNode)
	{
		BProgram* program = (BProgram*)readObject(programNode);
		shape->setProgram(program);
	}

	return true;
}
bool OscDocument::readNodeData(const BSonNode* son, BNode* node)
{
	const BString& visisbleStr = son->attrib("visible");
	if (visisbleStr.size())
	{
		bool visible = visisbleStr == "true";
		node->setVisible(visible);
	}

	const BString& optimizedStr = son->attrib("optimized");
	if (optimizedStr.size())
	{
		bool optimized = optimizedStr == "true";
		node->setOptimized(optimized);
	}

	BMatrix matrix;
	{
		const BString& positionStr = son->attrib("position");
		if (positionStr.size())
		{
			BVector position = stringToVector(positionStr);
			matrix.setPosition(position);
		}

		const BString& rotationStr = son->attrib("rotation");
		if (rotationStr.size())
		{
			BQuater rotation = stringToQuater(rotationStr);
			matrix.setRotate(rotation);
		}

		const BString& scaleStr = son->attrib("scale");
		if (scaleStr.size())
		{
			BVector scale = stringToVector(scaleStr);
			matrix.setScale(scale);
		}
	}
	node->setMatrix(matrix);

	for (int i = 0; i < son->childCount(); i++)
	{
		const BSonNode* child = son->child(i);
		BObjectHolder object = readObject(child);
		if (BShape* shape = object.as<BShape>())
			node->addShape(shape);
		else if (BPhysics* physics = object.as<BPhysics>())
			node->setPhysics(physics);
	}

	return true;
}
bool OscDocument::readTextureData(const BSonNode* son, BTexture* texture)
{
	const BString& blendStr = son->attrib("blend");
	if (blendStr.size())
	{
		BTexture::Blend blend = stringToBlend(blendStr);
		texture->setBlend(blend);
	}

	const BString& wrapStr = son->attrib("wrap");
	if (wrapStr.size())
	{
		BTexture::Wrap wrap = stringToWrap(wrapStr);
		texture->setWrap(wrap);
	}

	const BString& filterStr = son->attrib("filter");
	if (filterStr.size())
	{
		BTexture::Filter filter = stringToFilter(filterStr);
		texture->setFilter(filter);
	}

	const BString& mipmapStr = son->attrib("mipmap");
	if (mipmapStr.size())
	{
		bool mipmap = mipmapStr == "true";
		texture->setMipmap(mipmap);
	}

	const BString& blendColorStr = son->attrib("blendColor");
	if (blendColorStr.size())
	{
		BColor blendColor = stringToColor(blendColorStr);
		texture->setBlendColor(blendColor);
	}

	return true;
}

bool OscDocument::readScene(const BSonNode* son, BScene* scene)
{
	for (int i = 0; i < son->childCount(); i++)
	{
		const BSonNode* child = son->child(i);
		BObjectHolder object = readObject(child);
		if (BNode* node = object.as<BNode>())
			scene->insert(node);
		else if (BShape* shape = object.as<BShape>())
			scene->insert(shape);
	}
	return true;
}
bool OscDocument::readNode(const BSonNode* son, BNode* node)
{
	readObjectData(son, node);
	readNodeData(son, node);
	return true;
}
bool OscDocument::readLight(const BSonNode* son, BLight* light)
{
	readObjectData(son, light);
	readNodeData(son, light);

	const BString& typeStr = son->attrib("type");
	if (typeStr.size())
	{
		BLight::Type type = BLight::Type_Point;
		light->setType(type);
	}

	const BString& ambientStr = son->attrib("ambient");
	if (ambientStr.size())
	{
		BColor ambient = stringToColor(ambientStr);
		light->setAmbient(ambient);
	}

	const BString& diffuseStr = son->attrib("diffuse");
	if (diffuseStr.size())
	{
		BColor diffuse = stringToColor(diffuseStr);
		light->setDiffuse(diffuse);
	}

	const BString& specularStr = son->attrib("specular");
	if (specularStr.size())
	{
		BColor specular = stringToColor(specularStr);
		light->setSpecular(specular);
	}

	const BString& attenuationStr = son->attrib("attenuation");
	if (attenuationStr.size())
	{
		float attenuation = attenuationStr.toFloat();
		light->setAttenuation(attenuation);
	}

	const BString& attenuation2Str = son->attrib("attenuation2");
	if (attenuation2Str.size())
	{
		float attenuation2 = attenuation2Str.toFloat();
		light->setAttenuation2(attenuation2);
	}

	const BString& cutoffStr = son->attrib("cutoff");
	if (cutoffStr.size())
	{
		float cutoff = cutoffStr.toFloat();
		light->setCutoff(cutoff);
	}

	const BString& exponentStr = son->attrib("exponent");
	if (exponentStr.size())
	{
		float exponent = exponentStr.toFloat();
		light->setExponent(exponent);
	}

	const BString& directionStr = son->attrib("direction");
	if (directionStr.size())
	{
		BVector direction = stringToVector(directionStr);
		light->setDirection(direction);
	}

	return true;
}
bool OscDocument::readCamera(const BSonNode* son, BCamera* camera)
{
	readObjectData(son, camera);
	readNodeData(son, camera);

	const BString& centerStr = son->attrib("center");
	if (centerStr.size())
	{
		BVector center = stringToVector(centerStr);
		camera->setCenter(center);
	}

	const BString& upStr = son->attrib("up");
	if (upStr.size())
	{
		BVector up = stringToVector(upStr);
		camera->setUp(up);
	}

	const BString& orthoStr = son->attrib("ortho");
	if (orthoStr.size())
	{
		bool ortho = orthoStr == "true";
		camera->setOrtho(ortho);
	}

	const BString& fovyStr = son->attrib("fovy");
	if (fovyStr.size())
	{
		BReal fovy = fovyStr.toDouble();
		camera->setFovy(fovy);
	}

	const BString& aspectStr = son->attrib("aspect");
	if (aspectStr.size())
	{
		BReal aspect = aspectStr.toDouble();
		camera->setAspect(aspect);
	}

	const BString& nearStr = son->attrib("near");
	if (nearStr.size())
	{
		BReal near = nearStr.toDouble();
		camera->setNear(near);
	}

	const BString& farStr = son->attrib("far");
	if (farStr.size())
	{
		BReal far = farStr.toDouble();
		camera->setFar(far);
	}

	const BString& colorStr = son->attrib("color");
	if (colorStr.size())
	{
		BColor color = stringToColor(colorStr);
		camera->setColor(color);
	}

	const BString& lensWidthStr = son->attrib("lensWidth");
	if (lensWidthStr.size())
	{
		BReal lensWidth = lensWidthStr.toDouble();
		camera->setLensWidth(lensWidth);
	}

	const BString& lensHeightStr = son->attrib("lensHeight");
	if (lensHeightStr.size())
	{
		BReal lensHeight = lensHeightStr.toDouble();
		camera->setLensHeight(lensHeight);
	}

	const BString& pixelSizeStr = son->attrib("pixelSize");
	if (pixelSizeStr.size())
	{
		BSize pixelSize = stringToSize(pixelSizeStr);
		camera->setPixelSize(pixelSize);
	}

	return true;
}
bool OscDocument::readBillboard(const BSonNode* son, BBillboard* billboard)
{
	readObjectData(son, billboard);
	readShapeData(son, billboard);

	const BString& axisStr = son->attrib("axis");
	if (axisStr.size())
	{
		BVector axis = stringToVector(axisStr);
		billboard->setAxis(axis);
	}

	return true;
}
bool OscDocument::readGroup(const BSonNode* son, BGroup* group)
{
	readObjectData(son, group);
	for (int i = 0; i < son->childCount(); i++)
	{
		const BSonNode* child = son->child(i);
		BObjectHolder object = readObject(child);
		if (BNode* node = object.as<BNode>())
			group->insert(node);
		else if (BShape* shape = object.as<BShape>())
			group->insert(shape);
		else if (BConstraint* constraint = object.as<BConstraint>())
			group->insert(constraint);
		else if (BGroup* childGroup = object.as<BGroup>())
			group->addChild(childGroup);
	}
	return true;
}

bool OscDocument::readMesh(const BSonNode* son, BMesh* mesh)
{
	readObjectData(son, mesh);
	readShapeData(son, mesh);

	const BString& optimizedStr = son->attrib("optimized");
	if (optimizedStr.size())
	{
		bool optimized = optimizedStr == "true";
		mesh->setOptimized(optimized);
	}

	if (const BSonNode* verticesNode = son->child("vertices"))
	{
		BVectorArray* vertices = new BVectorArray();
		readVectorArray(verticesNode, vertices);
		mesh->setVertices(vertices);
	}

	if (const BSonNode* normalsNode = son->child("normals"))
	{
		BVectorArray* normals = new BVectorArray();
		readVectorArray(normalsNode, normals);
		mesh->setNormals(normals);
	}

	if (const BSonNode* coordsNode = son->child("texcoords"))
	{
		BCoordArray* texCoords = new BCoordArray();
		readCoordArray(coordsNode, texCoords);
		mesh->setTexCoords(texCoords);
	}

	if (const BSonNode* facesNode = son->child("faces"))
	{
		BFaceArray* faces = new BFaceArray();
		readFaceArray(facesNode, faces);
		mesh->setFaces(faces);
	}

	if (const BSonNode* colorsNode = son->child("colors"))
	{
		BColorArray* colors = new BColorArray();
		readColorArray(colorsNode, colors);
		mesh->setColors(colors);
	}

	return true;
}
bool OscDocument::readGeometry(const BSonNode* son, BGeometry* geometry)
{
	readObjectData(son, geometry);
	readShapeData(son, geometry);

	const BString& optimizedStr = son->attrib("optimized");
	if (optimizedStr.size())
	{
		bool optimized = optimizedStr == "true";
		geometry->setOptimized(optimized);
	}

	if (const BSonNode* verticesNode = son->child("vertices"))
	{
		BVectorArray* vertices = new BVectorArray();
		readVectorArray(verticesNode, vertices);
		geometry->setVertices(vertices);
	}

	if (const BSonNode* normalsNode = son->child("normals"))
	{
		BVectorArray* normals = new BVectorArray();
		readVectorArray(normalsNode, normals);
		geometry->setNormals(normals);
	}

	if (const BSonNode* coordsNode = son->child("texcoords"))
	{
		BCoordArray* texCoords = new BCoordArray();
		readCoordArray(coordsNode, texCoords);
		geometry->setTexCoords(texCoords);
	}

	for (int i = 0; i < son->childCount(); i++)
	{
		const BSonNode* child = son->child(i);
		if (child->name() == "element")
		{
			BElement* element = new BElement();
			readElement(child, element);
			geometry->addElement(element);
		}
	}

	return true;
}
bool OscDocument::readTextual(const BSonNode* son, BTextual* textual)
{
	readObjectData(son, textual);
	readShapeData(son, textual);

	const BString& sizefStr = son->attrib("sizef");
	if (sizefStr.size())
	{
		BRealSize size = stringToRealSize(sizefStr);
		textual->setSize(size);
	}

	const BString& alignStr = son->attrib("align");
	if (alignStr.size())
	{
		Align align = stringToAlign(alignStr);
		textual->setAlign(align);
	}

	const BString& fontStr = son->attrib("font");
	if (fontStr.size())
	{
		BFont* font = stringToFont(fontStr);
		textual->setFont(font);
	}

	const BString& glyphSizeStr = son->attrib("glyphSize");
	if (glyphSizeStr.size())
	{
		float glyphSize = glyphSizeStr.toFloat();
		textual->setGlyphSize(glyphSize);
	}
	const BString& text = son->text();
	textual->setText(text);

	if (const BSonNode* colorsNode = son->child("colors"))
	{
		BColorArray* colors = new BColorArray();
		readColorArray(colorsNode, colors);
		textual->setColors(colors);
	}

	return true;
}
bool OscDocument::readParticle(const BSonNode* son, BParticle* particle)
{
	readObjectData(son, particle);
	readShapeData(son, particle);
	return true;
}
bool OscDocument::readElement(const BSonNode* son, BElement* element)
{
	readObjectData(son, element);

	const BString& primitiveStr = son->attrib("primitive");
	if (primitiveStr.size())
	{
		Primitive primitive = stringToPrimitive(primitiveStr);
		element->setPrimitive(primitive);
	}

	const BString& firstStr = son->attrib("first");
	if (firstStr.size())
	{
		int first = firstStr.toInt();
		element->setFirst(first);
	}

	const BString& countStr = son->attrib("count");
	if (countStr.size())
	{
		int count = countStr.toInt();
		element->setCount(count);
	}

	if (const BSonNode* indicesNode = son->child("indices"))
	{
		BIndexArray* indices = new BIndexArray();
		readIndexArray(indicesNode, indices);
		element->setIndices(indices);
	}

	if (const BSonNode* piecesNode = son->child("pieces"))
	{
		BPieceArray* pieces = new BPieceArray();
		readPieceArray(piecesNode, pieces);
		element->setPieces(pieces);
	}

	return true;
}

bool OscDocument::readCube(const BSonNode* son, BCube* cube)
{
	readObjectData(son, cube);
	readShapeData(son, cube);

	const BString& lengthStr = son->attrib("length");
	if (lengthStr.size())
	{
		float length = lengthStr.toFloat();
		cube->setLength(length);
	}

	const BString& widthStr = son->attrib("width");
	if (widthStr.size())
	{
		float width = widthStr.toFloat();
		cube->setWidth(width);
	}

	const BString& heightStr = son->attrib("height");
	if (heightStr.size())
	{
		float height = heightStr.toFloat();
		cube->setHeight(height);
	}

	const BString& lengthSegmentsStr = son->attrib("lengthSegments");
	if (lengthSegmentsStr.size())
	{
		int lengthSegments = lengthSegmentsStr.toInt();
		cube->setLengthSegments(lengthSegments);
	}

	const BString& widthSegmentsStr = son->attrib("widthSegments");
	if (widthSegmentsStr.size())
	{
		int widthSegments = widthSegmentsStr.toInt();
		cube->setWidthSegments(widthSegments);
	}

	const BString& heightSegmentsStr = son->attrib("heightSegments");
	if (heightSegmentsStr.size())
	{
		int heightSegments = heightSegmentsStr.toInt();
		cube->setHeightSegments(heightSegments);
	}

	return true;
}
bool OscDocument::readCone(const BSonNode* son, BCone* cone)
{
	readObjectData(son, cone);
	readShapeData(son, cone);

	const BString& radiusStr = son->attrib("radius");
	if (radiusStr.size())
	{
		float radius = radiusStr.toFloat();
		cone->setRadius(radius);
	}

	const BString& heightStr = son->attrib("height");
	if (heightStr.size())
	{
		float height = heightStr.toFloat();
		cone->setHeight(height);
	}

	const BString& sidesStr = son->attrib("sides");
	if (sidesStr.size())
	{
		int sides = sidesStr.toInt();
		cone->setSides(sides);
	}

	const BString& segmentsStr = son->attrib("segments");
	if (segmentsStr.size())
	{
		int segments = segmentsStr.toInt();
		cone->setSegments(segments);
	}

	const BString& radiusSegmentsStr = son->attrib("radiusSegments");
	if (radiusSegmentsStr.size())
	{
		int radiusSegments = radiusSegmentsStr.toInt();
		cone->setBottomSegments(radiusSegments);
	}

	return true;
}
bool OscDocument::readCylinder(const BSonNode* son, BCylinder* cylinder)
{
	readObjectData(son, cylinder);
	readShapeData(son, cylinder);

	const BString& radiusStr = son->attrib("radius");
	if (radiusStr.size())
	{
		float radius = radiusStr.toFloat();
		cylinder->setRadius(radius);
	}

	const BString& heightStr = son->attrib("height");
	if (heightStr.size())
	{
		float height = heightStr.toFloat();
		cylinder->setHeight(height);
	}

	const BString& sidesStr = son->attrib("sides");
	if (sidesStr.size())
	{
		int sides = sidesStr.toInt();
		cylinder->setSides(sides);
	}

	const BString& heightSegmentsStr = son->attrib("heightSegments");
	if (heightSegmentsStr.size())
	{
		int heightSegments = heightSegmentsStr.toInt();
		cylinder->setHeightSegments(heightSegments);
	}

	const BString& radiusSegmentsStr = son->attrib("radiusSegments");
	if (radiusSegmentsStr.size())
	{
		int radiusSegments = radiusSegmentsStr.toInt();
		cylinder->setRadiusSegments(radiusSegments);
	}

	return true;
}
bool OscDocument::readSphere(const BSonNode* son, BSphere* sphere)
{
	readObjectData(son, sphere);
	readShapeData(son, sphere);

	const BString& radiusStr = son->attrib("radius");
	if (radiusStr.size())
	{
		float radius = radiusStr.toFloat();
		sphere->setRadius(radius);
	}

	const BString& sidesStr = son->attrib("sides");
	if (sidesStr.size())
	{
		int sides = sidesStr.toInt();
		sphere->setSides(sides);
	}

	const BString& segmentsStr = son->attrib("segments");
	if (segmentsStr.size())
	{
		int segments = segmentsStr.toInt();
		sphere->setSegments(segments);
	}

	return true;
}
bool OscDocument::readGeoSphere(const BSonNode* son, BGeoSphere* geoSphere)
{
	readObjectData(son, geoSphere);
	readShapeData(son, geoSphere);

	const BString& radiusStr = son->attrib("radius");
	if (radiusStr.size())
	{
		float radius = radiusStr.toFloat();
		geoSphere->setRadius(radius);
	}

	const BString& divideStr = son->attrib("divide");
	if (divideStr.size())
	{
		int divide = divideStr.toInt();
		geoSphere->setDivide(divide);
	}

	return true;
}
bool OscDocument::readTube(const BSonNode* son, BTube* tube)
{
	readObjectData(son, tube);
	readShapeData(son, tube);

	const BString& radiusStr = son->attrib("radius");
	if (radiusStr.size())
	{
		float radius = radiusStr.toFloat();
		tube->setRadius(radius);
	}

	const BString& heightStr = son->attrib("height");
	if (heightStr.size())
	{
		float height = heightStr.toFloat();
		tube->setHeight(height);
	}

	const BString& sidesStr = son->attrib("sides");
	if (sidesStr.size())
	{
		int sides = sidesStr.toInt();
		tube->setSides(sides);
	}

	const BString& heightSegmentsStr = son->attrib("heightSegments");
	if (heightSegmentsStr.size())
	{
		int heightSegments = heightSegmentsStr.toInt();
		tube->setHeightSegments(heightSegments);
	}

	const BString& radiusSegmentsStr = son->attrib("radiusSegments");
	if (radiusSegmentsStr.size())
	{
		int radiusSegments = radiusSegmentsStr.toInt();
		tube->setRadiusSegments(radiusSegments);
	}

	const BString& thicknessStr = son->attrib("thickness");
	if (thicknessStr.size())
	{
		float thickness = thicknessStr.toFloat();
		tube->setThickness(thickness);
	}

	return true;
}
bool OscDocument::readTorus(const BSonNode* son, BTorus* torus)
{
	readObjectData(son, torus);
	readShapeData(son, torus);

	const BString& radiusStr = son->attrib("radius");
	if (radiusStr.size())
	{
		float radius = radiusStr.toFloat();
		torus->setRadius(radius);
	}

	const BString& outerRadiusStr = son->attrib("outerRadius");
	if (outerRadiusStr.size())
	{
		float outerRadius = outerRadiusStr.toFloat();
		torus->setOuterRadius(outerRadius);
	}

	const BString& sidesStr = son->attrib("sides");
	if (sidesStr.size())
	{
		int sides = sidesStr.toInt();
		torus->setSides(sides);
	}

	const BString& segmentsStr = son->attrib("segments");
	if (segmentsStr.size())
	{
		int divide = segmentsStr.toInt();
		torus->setDivide(divide);
	}

	return true;
}
bool OscDocument::readSurface(const BSonNode* son, BSurface* surface)
{
	readObjectData(son, surface);
	readShapeData(son, surface);

	const BString& quadStr = son->attrib("quad");
	if (quadStr.size())
	{
		BQuadf quad = stringToQuad(quadStr);
		surface->setQuadEdges(quad);
	}

	const BString& horSegmentStr = son->attrib("horSegment");
	if (horSegmentStr.size())
	{
		int horSegment = horSegmentStr.toInt();
		surface->setHorizontalSegment(horSegment);
	}

	const BString& verSegmentStr = son->attrib("verSegment");
	if (verSegmentStr.size())
	{
		int verSegment = verSegmentStr.toInt();
		surface->setVerticalSegment(verSegment);
	}

	return true;
}
bool OscDocument::readTerrain(const BSonNode* son, BTerrain* terrain)
{
	readObjectData(son, terrain);
	readShapeData(son, terrain);

	const BString& alignStr = son->attrib("align");
	if (alignStr.size())
	{
		Align align = stringToAlign(alignStr);
		terrain->setAlign(align);
	}

	const BString& widthStr = son->attrib("width");
	if (widthStr.size())
	{
		float width = widthStr.toFloat();
		terrain->setWidth(width);
	}

	const BString& heightStr = son->attrib("height");
	if (heightStr.size())
	{
		float height = heightStr.toFloat();
		terrain->setHeight(height);
	}

	if (const BSonNode* elevationNode = son->child("elevation"))
	{
		BRealTable& elevation = terrain->elevation();
		readScalarTable(elevationNode, elevation);
		terrain->setElevation(elevation);
	}
	return true;
}

bool OscDocument::readMaterial(const BSonNode* son, BMaterial* material)
{
	readObjectData(son, material);

	const BString& ambientStr = son->attrib("ambient");
	if (ambientStr.size())
	{
		BColor ambient = stringToColor(ambientStr);
		material->setAmbient(ambient);
	}

	const BString& diffuseStr = son->attrib("diffuse");
	if (diffuseStr.size())
	{
		BColor diffuse = stringToColor(diffuseStr);
		material->setDiffuse(diffuse);
	}

	const BString& specularStr = son->attrib("specular");
	if (specularStr.size())
	{
		BColor specular = stringToColor(specularStr);
		material->setSpecular(specular);
	}

	const BString& emissionStr = son->attrib("emission");
	if (emissionStr.size())
	{
		BColor emission = stringToColor(emissionStr);
		material->setEmission(emission);
	}

	const BString& shininessStr = son->attrib("shininess");
	if (shininessStr.size())
	{
		BByte shininess = shininessStr.toInt();
		material->setShininess(shininess);
	}

	return material;
}
bool OscDocument::readImage(const BSonNode* son, BImage* image)
{
	readObjectData(son, image);
	readTextureData(son, image);

	const BString& fileName = son->attrib("file");
	if (ReadFile(fileName, image))
	{
		image->setFileName(fileName);
		image->setBlend(BTexture::Blend_Modulate);
	}
	else
	{
		message() << "OSC Error : Read image file failed : " << fileName;
	}

	const BString& formatStr = son->attrib("format");
	if (formatStr.size())
	{
		Format format = stringToFormat(formatStr);
		image->setFormat(format);
	}

	const BString& sizeStr = son->attrib("size");
	if (sizeStr.size())
	{
		BSize size = stringToSize(sizeStr);
		image->setSize(size);
	}

	if (const BSonNode* pixelsNode = son->child("pixels"))
	{
		BByteArray* pixels = new BByteArray();
		readByteArray(pixelsNode, pixels);
		image->setPixels(pixels);
	}
	return image;
}
bool OscDocument::readPixmap(const BSonNode* son, BPixmap* pixmap)
{
	readObjectData(son, pixmap);
	readTextureData(son, pixmap);

	const BString& sizeStr = son->attrib("size");
	if (sizeStr.size())
	{
		BSize size = stringToSize(sizeStr);
		pixmap->setSize(size);
	}

	const BString& colorStr = son->attrib("color");
	if (colorStr.size())
	{
		BColor color = stringToColor(colorStr);
		pixmap->setColor(color);
	}

	return pixmap;
}
bool OscDocument::readProgram(const BSonNode* son, BProgram* program)
{
	readObjectData(son, program);

	for (int i = 0; i < son->childCount(); i++)
	{
		const BSonNode* child = son->child(i);
		if (child->name() == "shader")
		{
			BShader* shader = new BShader();
			readShader(child, shader);
			program->addShader(shader);
		}
		else if (child->name() == "uniform")
		{
			BUniform* uniform = new BUniform();
			readUniform(child, uniform);
			program->addUniform(uniform);
		}
	}

	return true;
}
bool OscDocument::readShader(const BSonNode* son, BShader* shader)
{
	readObjectData(son, shader);

	const BString& typeStr = son->attrib("type");
	if (typeStr.size())
	{
		BShader::Type type = stringToShaderType(typeStr);
		shader->setType(type);
	}

	shader->setText(son->text());

	return shader;
}
bool OscDocument::readUniform(const BSonNode* son, BUniform* uniform)
{
	readObjectData(son, uniform);

	const BString& signStr = son->attrib("sign");
	uniform->setSign(signStr);

	const BString& typeStr = son->attrib("type");
	if (typeStr.size())
	{
		BUniform::Type type = stringToUniformType(typeStr);
		uniform->setType(type);
	}

	const BString& sizeStr = son->attrib("size");
	if (sizeStr.size())
	{
		int size = sizeStr.toInt();
		uniform->setSize(size);
	}

	return uniform;
}
bool OscDocument::readScript(const BSonNode* son, BScript* script)
{
	readObjectData(son, script);

	for (int i = 0; i < son->childCount(); i++)
	{
		const BSonNode* child = son->child(i);
		if (child->name() == "sources")
		{
			const BString& text = child->text();
			BStringList sources = text.split(';');
			for (auto it = sources.begin(); it.valid(); ++it)
			{
				BSource* source = new BSource(*it);
				script->insertSource(source);
			}
			continue;
		}
		if (child->name() == "breakpoints")
		{
			const BString& text = child->text();
			BStringList breakpoints = text.split(';');
			for (auto it = breakpoints.begin(); it.valid(); ++it)
			{
				script->insertBreakpoint(*it);
			}
			continue;
		}
		if (child->name() == "sequence")
		{
			BExpHolderArray sequence;
			for (int ei = 0; ei < child->childCount(); ei++)
			{
				const BSonNode* expNode = child->child(ei);
				BExp* exp = new BExp();
				exp->syntax = stringToSyntax(expNode->name());
				readScriptExp(expNode, exp);
				sequence.append(exp);
			}
			script->setSequence(sequence);
		}
	}

	return true;
}

bool OscDocument::readScriptExp(const BSonNode* son, BExp* exp)
{
	exp->info = son->attrib("info");
	exp->type = son->attrib("type");
	exp->name = son->attrib("name");
	exp->value = stringToValue(son->attrib("value"));
	for (int i = 0; i < son->childCount(); i++)
	{
		const BSonNode* child = son->child(i);
		BExp* param = new BExp();
		param->syntax = stringToSyntax(child->name());
		readScriptExp(child, param);
		exp->params.append(param);
	}
	return true;
}
bool OscDocument::readVectorArray(const BSonNode* son, BVectorArray* vertices)
{
	const BString& sizeStr = son->attrib("size");
	int size = sizeStr.toInt();
	vertices->resize(size);
	const BString& text = son->text();
	BString value;
	int index = 0;
	int end = 0;
	int pos = 0;
	while (pos < text.size() && index < size)
	{
		end = text.find(',', pos);
		text.substr(value, pos, end);
		float x = value.toFloat();
		pos = end + 1;

		end = text.find(',', pos);
		text.substr(value, pos, end);
		float y = value.toFloat();
		pos = end + 1;

		end = text.find(',', pos);
		text.substr(value, pos, end);
		float z = value.toFloat();
		pos = end + 1;

		(*vertices)[index++].set(x, y, z);
	}
	return true;
}
bool OscDocument::readCoordArray(const BSonNode* son, BCoordArray* coords)
{
	const BString& sizeStr = son->attrib("size");
	int size = sizeStr.toInt();
	coords->resize(size);
	const BString& text = son->text();
	BString value;
	int index = 0;
	int end = 0;
	int pos = 0;
	while (pos < text.size() && index < size)
	{
		end = text.find(',', pos);
		text.substr(value, pos, end);
		float x = value.toFloat();
		pos = end + 1;

		end = text.find(',', pos);
		text.substr(value, pos, end);
		float y = value.toFloat();
		pos = end + 1;

		(*coords)[index++].set(x, y);
	}
	return true;
}
bool OscDocument::readColorArray(const BSonNode* son, BColorArray* colors)
{
	const BString& sizeStr = son->attrib("size");
	int size = sizeStr.toInt();
	colors->resize(size);
	const BString& text = son->text();
	BString value;
	int index = 0;
	int end = 0;
	int pos = 0;
	while (pos < text.size() && index < size)
	{
		end = text.find(',', pos);
		text.substr(value, pos, end);
		BByte r = value.toInt();
		pos = end + 1;

		end = text.find(',', pos);
		text.substr(value, pos, end);
		BByte g = value.toInt();
		pos = end + 1;

		end = text.find(',', pos);
		text.substr(value, pos, end);
		BByte b = value.toInt();
		pos = end + 1;

		end = text.find(',', pos);
		text.substr(value, pos, end);
		BByte a = value.toInt();
		pos = end + 1;

		(*colors)[index++].set(r, g, b, a);
	}
	return true;
}
bool OscDocument::readFaceArray(const BSonNode* son, BFaceArray* faces)
{
	const BString& sizeStr = son->attrib("size");
	int size = sizeStr.toInt();
	faces->resize(size);
	const BString& text = son->text();
	BString value;
	int index = 0;
	int end = 0;
	int pos = 0;
	while (pos < text.size() && index < size)
	{
		end = text.find(',', pos);
		text.substr(value, pos, end);
		unsigned int a = value.toUInt();
		pos = end + 1;

		end = text.find(',', pos);
		text.substr(value, pos, end);
		unsigned int b = value.toUInt();
		pos = end + 1;

		end = text.find(',', pos);
		text.substr(value, pos, end);
		unsigned int c = value.toUInt();
		pos = end + 1;

		(*faces)[index++].set(a, b, c);
	}
	return true;
}
bool OscDocument::readIndexArray(const BSonNode* son, BIndexArray* indices)
{
	const BString& sizeStr = son->attrib("size");
	int size = sizeStr.toInt();
	indices->resize(size);
	const BString& text = son->text();
	BString value;
	int index = 0;
	int end = 0;
	int pos = 0;
	while (pos < text.size() && index < size)
	{
		end = text.find(',', pos);
		text.substr(value, pos, end);
		unsigned int i = value.toUInt();
		pos = end + 1;

		(*indices)[index++] = i;
	}
	return true;
}
bool OscDocument::readPieceArray(const BSonNode* son, BPieceArray* pieces)
{
	const BString& sizeStr = son->attrib("size");
	int size = sizeStr.toInt();
	pieces->resize(size);
	const BString& text = son->text();
	BString value;
	int index = 0;
	int end = 0;
	int pos = 0;
	while (pos < text.size() && index < size)
	{
		end = text.find(',', pos);
		text.substr(value, pos, end);
		unsigned int v = value.toUInt();
		pos = end + 1;

		end = text.find(',', pos);
		text.substr(value, pos, end);
		unsigned int vn = value.toUInt();
		pos = end + 1;

		end = text.find(',', pos);
		text.substr(value, pos, end);
		unsigned int vt = value.toUInt();
		pos = end + 1;

		BPiece& piece = (*pieces)[index++];
		piece.v() = v;
		piece.vn() = vn;
		piece.vt() = vt;
	}
	return true;
}
bool OscDocument::readScalarTable(const BSonNode* son, BRealTable& stable)
{
	const BString& rowStr = son->attrib("row");
	int row = rowStr.toInt();
	const BString& columnStr = son->attrib("column");
	int column = columnStr.toInt();

	stable.resize(row, column);
	int size = stable.size();
	BReal* data = stable.data();

	const BString& text = son->text();
	BString value;
	int index = 0;
	int end = 0;
	int pos = 0;
	while (pos < text.size() && index < size)
	{
		end = text.find(',', pos);
		text.substr(value, pos, end);
		BReal v = value.toReal();
		pos = end + 1;

		data[index++] = v;
	}
	return true;
}
bool OscDocument::readByteArray(const BSonNode* son, BByteArray* bytes)
{
	const BString& sizeStr = son->attrib("size");
	int size = sizeStr.toInt();
	bytes->resize(size);
	const BString& text = son->text();
	BString value;
	int index = 0;
	int end = 0;
	int pos = 0;
	while (pos < text.size() && index < size)
	{
		end = text.find(',', pos);
		text.substr(value, pos, end);
		BByte v = value.toInt();
		pos = end + 1;

		(*bytes)[index++] = v;
	}
	return true;
}

BSonNode* OscDocument::writeObject(const BObject* object) const
{
	BString type = object->className();
	if (type.beginWith('B'))
		type.remove(0);
	type.lower();
	int id = _writeObjectMap(object);
	if (id > 0)
	{
		BSonNode* node = new BSonNode(type);
		node->setAttrib("id", id);
		return node;
	}
	OscDocument::writeFunc write = OscDocument::_writeFuncMap(type);
	if (!write)
	{
		message() << "OSC Error : Write object failed : No read func for " << type;
		return 0;
	}
	BSonNode* node = new BSonNode(type);
	if (!(this->*write)(node, object))
	{
		message() << "OSC Error : Write object failed " << type;
		delete node;
		return 0;
	}
	if (object->ref_count() > 1)
	{
		id = _writeObjectMap.size() + 1;
		_writeObjectMap.insert(object, id);
		node->setAttrib("id", id);
	}
	return node;
}

bool OscDocument::writeObjectData(BSonNode* son, const BObject* object)
{
	const BString& name = object->name();
	if (name.size())
		son->setAttrib("name", name);

	if (object->enabled())
		son->setAttrib("enabled", "true");
	else
		son->setAttrib("enabled", "false");

	return son;
}
bool OscDocument::writeNodeData(BSonNode* son, const BNode* node)
{
	if (!node)
		return false;

	const char* visibleStr = stringOfBool(node->visible());
	son->setAttrib("visible", visibleStr);

	const char* optimizedStr = stringOfBool(node->optimized());
	son->setAttrib("optimized", optimizedStr);

	const BMatrix& matrix = node->matrix();
	BString positionStr = stringOfVector(matrix.position());
	son->setAttrib("position", positionStr);

	BString rotationStr = stringOfQuater(matrix.rotate());
	son->setAttrib("rotation", rotationStr);

	BString scaleStr = stringOfVector(matrix.scale());
	son->setAttrib("scale", scaleStr);

	for (int i = 0; i < node->shapeCount(); i++)
	{
		const BShape* shape = node->shape(i);
		BSonNode* child = writeObject(shape);
		son->addChild(child);
	}
	return true;
}
bool OscDocument::writeShapeData(BSonNode* son, const BShape* shape)
{
	if (!shape)
		return false;

	writeObjectData(son, shape);
	bool visible = shape->visible();
	son->setAttrib("visible", stringOfBool(visible));

	bool lighting = shape->lighting();
	son->setAttrib("lighting", stringOfBool(lighting));

	bool cullback = shape->cullback();
	son->setAttrib("cullback", stringOfBool(cullback));

	bool depthTest = shape->depthTest();
	son->setAttrib("depthTest", stringOfBool(depthTest));

	bool pointSmooth = shape->pointSmooth();
	son->setAttrib("pointSmooth", stringOfBool(pointSmooth));

	bool lineSmooth = shape->lineSmooth();
	son->setAttrib("lineSmooth", stringOfBool(lineSmooth));

	bool polygonSmooth = shape->polygonSmooth();
	son->setAttrib("polygonSmooth", stringOfBool(polygonSmooth));

	int lineWidth = shape->lineWidth();
	son->setAttrib("lineWidth", lineWidth);

	int pointSize = shape->pointSize();
	son->setAttrib("pointSize", pointSize);

	PolyMode polyMode = shape->polyMode();
	son->setAttrib("polyMode", stringOfPolyMode(polyMode));

	bool transparent = shape->transparent();
	son->setAttrib("transparent", stringOfBool(transparent));

	const BMatrix& matrix = shape->matrix();
	son->setAttrib("position", stringOfVector(matrix.position()));
	son->setAttrib("rotation", stringOfQuater(matrix.rotate()));
	son->setAttrib("scale", stringOfVector(matrix.scale()));

	const BString& colorStr = stringOfColor(shape->color());
	son->setAttrib("color", colorStr);

	if (BMaterial* material = shape->material())
	{
		son->addChild(writeObject(material));
	}
	if (BTexture* texture = shape->texture())
	{
		son->addChild(writeObject(texture));
	}
	if (BProgram* program = shape->program())
	{
		son->addChild(writeObject(program));
	}
	return true;
}
bool OscDocument::writeTextureData(BSonNode* son, const BTexture* texture)
{
	if (!texture)
		return false;

	const BString& blendStr = stringOfBlend(texture->blend());
	son->setAttrib("blend", blendStr);

	const BString& filterStr = stringOfFilter(texture->filter());
	son->setAttrib("filter", filterStr);

	const BString& wrapStr = stringOfWrap(texture->wrap());
	son->setAttrib("wrap", wrapStr);

	bool mipmap = texture->mipmap();
	son->setAttrib("mipmap", stringOfBool(mipmap));

	const BString& blendColorStr = stringOfColor(texture->blendColor());
	son->setAttrib("blendColor", blendColorStr);

	return true;
}

bool OscDocument::writeScene(BSonNode* son, const BScene* scene)
{
	for (int i = 0; i < scene->shapeCount(); i++)
	{
		const BShape* shape = scene->shape(i);
		BSonNode* child = writeObject(shape);
		if (child == 0)
		{
			message() << "OSC Error :  write shape failed : " << shape->name();
			return false;
		}
		son->addChild(child);
	}
	for (int i = 0; i < scene->nodeCount(); i++)
	{
		const BNode* node = scene->node(i);
		BSonNode* child = writeObject(node);
		if (child == 0)
		{
			message() << "OSC Error :  write node failed : " << node->name();
			return false;
		}
		son->addChild(child);
	}
	for (int i = 0; i < scene->constraintCount(); i++)
	{
		const BConstraint* constraint = scene->constraint(i);
		BSonNode* child = writeObject(constraint);
		if (child == 0)
		{
			message() << "OSC Error :  write node failed : " << constraint->name();
			return false;
		}
		son->addChild(child);
	}
	for (int i = 0; i < scene->groupCount(); i++)
	{
		const BGroup* group = scene->group(i);
		BSonNode* child = writeObject(group);
		if (child == 0)
		{
			message() << "OSC Error :  write node failed : " << group->name();
			return false;
		}
		son->addChild(child);
	}
	return true;
}
bool OscDocument::writeNode(BSonNode* son, const BNode* node)
{
	writeObjectData(son, node);
	writeNodeData(son, node);
	return true;
}
bool OscDocument::writeLight(BSonNode* son, const BLight* light)
{
	writeObjectData(son, light);
	writeNodeData(son, light);

	const BString& typeStr = stringOfLightType(light->type());
	son->setAttrib("type", typeStr);

	const BString& ambientStr = stringOfColor(light->ambient());
	son->setAttrib("ambient", ambientStr);

	const BString& diffuseStr = stringOfColor(light->diffuse());
	son->setAttrib("diffuse", diffuseStr);

	const BString& specularStr = stringOfColor(light->specular());
	son->setAttrib("specular", specularStr);

	float attenuation = light->attenuation();
	son->setAttrib("attenuation", attenuation);

	float attenuation2 = light->attenuation2();
	son->setAttrib("attenuation2", attenuation2);

	float cutoff = light->cutoff();
	son->setAttrib("cutoff", cutoff);

	float exponent = light->exponent();
	son->setAttrib("exponent", exponent);

	const BString& directionStr = stringOfVector(light->direction());
	son->setAttrib("direction", directionStr);

	return true;
}
bool OscDocument::writeCamera(BSonNode* son, const BCamera* camera)
{
	writeObjectData(son, camera);
	writeNodeData(son, camera);

	const BString& centerStr = stringOfVector(camera->center());
	son->setAttrib("center", centerStr);

	const BString& upStr = stringOfVector(camera->up());
	son->setAttrib("up", upStr);

	BReal near = camera->near();
	son->setAttrib("near", near);

	BReal far = camera->far();
	son->setAttrib("far", far);

	return true;
}
bool OscDocument::writeGroup(BSonNode* son, const BGroup* group)
{
	for (int i = 0; i < group->shapeCount(); i++)
	{
		const BShape* shape = group->shape(i);
		BSonNode* child = writeObject(shape);
		if (child == 0)
		{
			message() << "OSC Error :  write shape failed : " << shape->name();
			return false;
		}
		son->addChild(child);
	}
	for (int i = 0; i < group->nodeCount(); i++)
	{
		const BNode* node = group->node(i);
		BSonNode* child = writeObject(node);
		if (child == 0)
		{
			message() << "OSC Error :  write node failed : " << node->name();
			return false;
		}
		son->addChild(child);
	}
	for (int i = 0; i < group->constraintCount(); i++)
	{
		const BConstraint* constraint = group->constraint(i);
		BSonNode* child = writeObject(constraint);
		if (child == 0)
		{
			message() << "OSC Error :  write node failed : " << constraint->name();
			return false;
		}
		son->addChild(child);
	}
	for (int i = 0; i < group->childCount(); i++)
	{
		const BGroup* childGroup = group->child(i);
		BSonNode* child = writeObject(childGroup);
		if (child == 0)
		{
			message() << "OSC Error :  write node failed : " << childGroup->name();
			return false;
		}
		son->addChild(child);
	}
	return true;
}

bool OscDocument::writeMesh(BSonNode* son, const BMesh* mesh)
{
	writeObjectData(son, mesh);
	writeShapeData(son, mesh);

	bool optimized = mesh->optimized();
	son->setAttrib("optimized", stringOfBool(optimized));

	const BVectorArray* vertices = mesh->vertices();
	if (vertices)
	{
		BSonNode* verticesSon = son->addChild("vertices");
		writeVectorArray(verticesSon, vertices);
	}
	const BVectorArray* normals = mesh->normals();
	if (normals)
	{
		BSonNode* normalsNode = son->addChild("normals");
		writeVectorArray(normalsNode, normals);
	}
	const BCoordArray* texCoords = mesh->texCoords();
	if (texCoords)
	{
		BSonNode* coordsNode = son->addChild("texcoords");
		writeCoordArray(coordsNode, texCoords);
	}
	const BFaceArray* faces = mesh->faces();
	if (faces)
	{
		BSonNode* facesNode = son->addChild("faces");
		writeFaceArray(facesNode, faces);
	}

	return true;
}
bool OscDocument::writeGeometry(BSonNode* son, const BGeometry* geometry)
{
	writeObjectData(son, geometry);
	writeShapeData(son, geometry);

	bool optimized = geometry->optimized();
	son->setAttrib("optimized", stringOfBool(optimized));

	const BVectorArray* vertices = geometry->vertices();
	if (vertices)
	{
		BSonNode* verticesNode = son->addChild("vertices");
		writeVectorArray(verticesNode, vertices);
	}

	const BVectorArray* normals = geometry->normals();
	if (normals)
	{
		BSonNode* normalsNode = son->addChild("normals");
		writeVectorArray(normalsNode, normals);
	}
	const BCoordArray* texCoords = geometry->texCoords();
	if (texCoords)
	{
		BSonNode* coordsNode = son->addChild("texcoords");
		writeCoordArray(coordsNode, texCoords);
	}
	for (int i = 0; i < geometry->elementCount(); i++)
	{
		const BElement* element = geometry->element(i);
		BSonNode* elementNode = writeObject(element);
		son->addChild(elementNode);
	}
	return true;
}
bool OscDocument::writeBillboard(BSonNode* son, const BBillboard* billboard)
{
	writeObjectData(son, billboard);
	writeShapeData(son, billboard);

	const BString& quadStr = stringOfQuad(billboard->quad());
	son->setAttrib("quad", quadStr);

	const BString& axisStr = stringOfVector(billboard->axis());
	son->setAttrib("axis", axisStr);

	return true;
}
bool OscDocument::writeTextual(BSonNode* son, const BTextual* textual)
{
	writeObjectData(son, textual);
	writeShapeData(son, textual);

	const BString& quadStr = stringOfQuad(textual->quad());
	son->setAttrib("quad", quadStr);

	const BString& alignStr = stringOfAlign(textual->align());
	son->setAttrib("align", alignStr);

	const BString& fontStr = stringOfFont(textual->font());
	son->setAttrib("font", fontStr);

	BReal glyphSize = textual->glyphSize();
	son->setAttrib("glyphSize", glyphSize);

	const BString& text = textual->text();
	son->setText(text);

	const BColorArray* colors = textual->colors();
	{
		BSonNode* colorsNode = son->addChild("colors");
		writeColorArray(colorsNode, colors);
	}

	return true;
}
bool OscDocument::writeParticle(BSonNode* son, const BParticle* particle)
{
	return false;
}
bool OscDocument::writeElement(BSonNode* son, const BElement* element)
{
	writeObjectData(son, element);

	const BString& primitiveStr = stringOfPrimitive(element->primitive());
	son->setAttrib("primitive", primitiveStr);

	int first = element->first();
	son->setAttrib("first", first);

	int count = element->count();
	son->setAttrib("count", count);

	int group = 0;
	switch (element->primitive())
	{
	case Primitive_Points:			group = 1;	break;
	case Primitive_Lines:			group = 2;	break;
	case Primitive_LineStrip:		group = 2;	break;
	case Primitive_LineLoop:		group = 2;	break;
	case Primitive_Triangles:		group = 3;	break;
	case Primitive_TriangleStrip:	group = 3;	break;
	case Primitive_TriangleFan:		group = 3;	break;
	case Primitive_Quads:			group = 4;	break;
	case Primitive_QuadStrip:		group = 4;	break;
	}

	BIndexArray* indices = element->indices();
	if (indices)
	{
		BSonNode* indicesNode = son->addChild("indices");
		writeIndexArray(indicesNode, indices, group);
	}
	BPieceArray* pieces = element->pieces();
	if (pieces)
	{
		BSonNode* child = son->addChild("pieces");
		writePieceArray(child, pieces, group);
	}
	return true;
}

bool OscDocument::writeCube(BSonNode* son, const BCube* cube)
{
	writeObjectData(son, cube);
	writeShapeData(son, cube);

	BReal length = cube->length();
	son->setAttrib("length", length);

	BReal width = cube->width();
	son->setAttrib("width", width);

	BReal height = cube->height();
	son->setAttrib("height", height);

	int lengthSegments = cube->lengthSegments();
	son->setAttrib("lengthSegments", lengthSegments);

	int widthSegments = cube->widthSegments();
	son->setAttrib("widthSegments", widthSegments);

	int heightSegments = cube->heightSegments();
	son->setAttrib("heightSegments", heightSegments);

	return true;
}
bool OscDocument::writeCone(BSonNode* son, const BCone* cone)
{
	writeObjectData(son, cone);
	writeShapeData(son, cone);

	BReal radius = cone->radius();
	son->setAttrib("radius", radius);

	BReal height = cone->height();
	son->setAttrib("height", height);

	int sides = cone->sides();
	son->setAttrib("sides", sides);

	int segments = cone->segments();
	son->setAttrib("segments", segments);

	int radiusSegments = cone->radiusSegments();
	son->setAttrib("radiusSegments", radiusSegments);

	return true;
}
bool OscDocument::writeCylinder(BSonNode* son, const BCylinder* cylinder)
{
	writeObjectData(son, cylinder);
	writeShapeData(son, cylinder);

	BReal radius = cylinder->radius();
	son->setAttrib("radius", radius);

	BReal height = cylinder->height();
	son->setAttrib("height", height);

	int sides = cylinder->sides();
	son->setAttrib("sides", sides);

	int heightSegments = cylinder->heightSegments();
	son->setAttrib("heightSegments", heightSegments);

	int radiusSegments = cylinder->radiusSegments();
	son->setAttrib("radiusSegments", radiusSegments);

	return true;
}
bool OscDocument::writeSphere(BSonNode* son, const BSphere* sphere)
{
	writeObjectData(son, sphere);
	writeShapeData(son, sphere);

	BReal radius = sphere->radius();
	son->setAttrib("radius", radius);

	int sides = sphere->sides();
	son->setAttrib("sides", sides);

	int segments = sphere->segments();
	son->setAttrib("segments", segments);

	return true;
}
bool OscDocument::writeGeoSphere(BSonNode* son, const BGeoSphere* geoSphere)
{
	writeObjectData(son, geoSphere);
	writeShapeData(son, geoSphere);

	BReal radius = geoSphere->radius();
	son->setAttrib("radius", radius);

	int divide = geoSphere->divide();
	son->setAttrib("divide", divide);

	return true;
}
bool OscDocument::writeTube(BSonNode* son, const BTube* tube)
{
	writeObjectData(son, tube);
	writeShapeData(son, tube);

	BReal radius = tube->radius();
	son->setAttrib("radius", radius);

	BReal height = tube->height();
	son->setAttrib("height", height);

	int sides = tube->sides();
	son->setAttrib("sides", sides);

	int heightSegments = tube->heightSegments();
	son->setAttrib("heightSegments", heightSegments);

	int radiusSegments = tube->radiusSegments();
	son->setAttrib("radiusSegments", radiusSegments);

	BReal thickness = tube->thickness();
	son->setAttrib("thickness", thickness);

	return true;
}
bool OscDocument::writeTorus(BSonNode* son, const BTorus* torus)
{
	writeObjectData(son, torus);
	writeShapeData(son, torus);

	BReal radius = torus->radius();
	son->setAttrib("radius", radius);

	BReal outerRadius = torus->outerRadius();
	son->setAttrib("outerRadius", outerRadius);

	int sides = torus->sides();
	son->setAttrib("sides", sides);

	int divide = torus->divide();
	son->setAttrib("segments", divide);

	return true;
}
bool OscDocument::writeSurface(BSonNode* son, const BSurface* surface)
{
	writeObjectData(son, surface);
	writeShapeData(son, surface);

	const BString& quadStr = stringOfQuad(surface->quadEdges());
	son->setAttrib("quad", quadStr);

	int horSegment = surface->horizontalSegment();
	son->setAttrib("horSegment", horSegment);

	int verSegment = surface->verticalSegment();
	son->setAttrib("verSegment", verSegment);

	return true;
}
bool OscDocument::writeTerrain(BSonNode* son, const BTerrain* terrain)
{
	writeObjectData(son, terrain);
	writeShapeData(son, terrain);

	const BString& alignStr = stringOfAlign(terrain->align());
	son->setAttrib("align", alignStr);

	BReal width = terrain->width();
	son->setAttrib("width", width);

	BReal height = terrain->height();
	son->setAttrib("height", height);

	const BFloatTable& elevation = terrain->elevation();
	if (elevation.size())
	{
		BSonNode* child = son->addChild("elevation");
		writeFloatTable(child, elevation);
	}

	return true;
}

bool OscDocument::writeMaterial(BSonNode* son, const BMaterial* material)
{
	writeObjectData(son, material);

	const BString& ambientStr = stringOfColor(material->ambient());
	son->setAttrib("ambient", ambientStr);

	const BString& diffuseStr = stringOfColor(material->diffuse());
	son->setAttrib("diffuse", diffuseStr);

	const BString& specularStr = stringOfColor(material->specular());
	son->setAttrib("specular", specularStr);

	const BString& emissionStr = stringOfColor(material->emission());
	son->setAttrib("emission", emissionStr);

	BByte shininess = material->shininess();
	son->setAttrib("shininess", shininess);

	return true;
}
bool OscDocument::writeImage(BSonNode* son, const BImage* image)
{
	writeObjectData(son, image);
	writeTextureData(son, image);
	const BString& fileName = image->fileName();
	if (fileName.size())
	{
		son->setAttrib("file", fileName);
	}
	else
	{
		const BString& formatStr = stringOfFormat(image->format());
		son->setAttrib("format", formatStr);

		const BString& sizeStr = stringOfSize(image->size());
		son->setAttrib("size", sizeStr);

		const BByteArray* pixels = image->pixels();
		if (pixels)
		{
			BSonNode* child = son->addChild("pixels");
			writeByteArray(child, pixels, image->width());
		}
	}
	return true;
}
bool OscDocument::writePixmap(BSonNode* son, const BPixmap* pixmap)
{
	writeObjectData(son, pixmap);
	writeTextureData(son, pixmap);

	const BString& sizeStr = stringOfSize(pixmap->size());
	son->setAttrib("size", sizeStr);

	const BString& backgroundStr = stringOfColor(pixmap->color());
	son->setAttrib("background", backgroundStr);

	return true;
}
bool OscDocument::writeProgram(BSonNode* son, const BProgram* program)
{
	writeObjectData(son, program);
	for (int i = 0; i < program->shaderCount(); i++)
	{
		const BShader* shader = program->shader(i);
		writeObject(shader);
	}
	for (int i = 0; i < program->uniformCount(); i++)
	{
		const BUniform* uniform = program->uniform(i);
		writeObject(uniform);
	}
	return true;
}
bool OscDocument::writeShader(BSonNode* son, const BShader* shader)
{
	writeObjectData(son, shader);

	const BString& typeStr = stringOfShaderType(shader->type());
	son->setAttrib("type", typeStr);

	son->setText(shader->text());

	return true;
}
bool OscDocument::writeUniform(BSonNode* son, const BUniform* uniform)
{
	writeObjectData(son, uniform);

	const BString& sign = uniform->sign();
	son->setAttrib("sign", sign);

	const BString& typeStr = stringOfUniformType(uniform->type());
	son->setAttrib("type", typeStr);

	int size = uniform->size();
	son->setAttrib("size", size);

	return true;
}
bool OscDocument::writeScript(BSonNode* son, const BScript* script)
{
	writeObjectData(son, script);

	if (int count = script->sourceCount())
	{
		_text.reset();
		for (int i = 0; i < count; i++)
		{
			_text << script->source(i)->name() << ";\n";
		}
		_text -= ";\n";
		BSonNode* child = son->addChild("sources");
		child->setText(_text);
	}
	if (int count = script->breakpointCount() > 0)
	{
		_text.reset();
		for (int i = 0; i < count; i++)
		{
			_text << script->breakpoint(i) << ";\n";
		}
		_text -= ";\n";
		BSonNode* child = son->addChild("breakpoints");
		child->setText(_text);
	}
	const BExpHolderArray& sequence = script->sequence();
	if (int size = sequence.size())
	{
		BSonNode* child = son->addChild("sequence");
		for (int i = 0; i < size; i++)
		{
			BExp* exp = sequence[i];
			const BString& name = stringOfSyntax(exp->syntax);
			BSonNode* expNode = child->addChild(name);
			writeScriptExp(expNode, exp);
		}
	}
	return true;
}

bool OscDocument::writeScriptExp(BSonNode* son, const BExp* exp)
{
	if (exp->info.size())
		son->setAttrib("info", exp->info);
	if (exp->type.size())
		son->setAttrib("type", exp->type);
	if (exp->name.size())
		son->setAttrib("name", exp->name);
	const BString& valueStr = stringOfValue(exp->value);
	if (valueStr.size())
		son->setAttrib("value", valueStr);
	for (int i = 0; i < exp->params.size(); i++)
	{
		BExp* param = exp->params[i];
		const BString& name = stringOfSyntax(param->syntax);
		BSonNode* paramNode = son->addChild(name);
		writeScriptExp(paramNode, param);
	}
	return true;
}
bool OscDocument::writeVectorArray(BSonNode* son, const BVectorArray* vertices)
{
	son->setAttrib("size", vertices->size());
	BString& text = (BString&)son->text();
	text.reset();

	SonFormat fmt(son->format());
	if (fmt.end_post == '\n')
	{
		for (int i = 0; i < vertices->size(); i++)
		{
			const BVector& v = vertices->at(i);
			text << v.x() << ',' << v.y() << ',' << v.z() << ',' << '\n';
		}
		text -= ",\n";
	}
	else
	{
		for (int i = 0; i < vertices->size(); i++)
		{
			const BVector& v = vertices->at(i);
			text << v.x() << ',' << v.y() << ',' << v.z() << ',';
		}
		text -= ',';
	}
	return true;
}
bool OscDocument::writeCoordArray(BSonNode* son, const BCoordArray* coords)
{
	son->setAttrib("size", coords->size());
	BString& text = (BString&)son->text();
	text.reset();

	SonFormat fmt(son->format());
	if (fmt.end_post == '\n')
	{
		for (int i = 0; i < coords->size(); i++)
		{
			const BCoord& c = coords->at(i);
			text << c.x() << ',' << c.y() << ',' << '\n';
		}
		text -= ",\n";
	}
	else
	{
		for (int i = 0; i < coords->size(); i++)
		{
			const BCoord& c = coords->at(i);
			text << c.x() << ',' << c.y() << ',';
		}
		text -= ',';
	}
	return true;
}
bool OscDocument::writeColorArray(BSonNode* son, const BColorArray* colors)
{
	son->setAttrib("size", colors->size());
	BString& text = (BString&)son->text();
	text.reset();

	SonFormat fmt(son->format());
	if (fmt.end_post == '\n')
	{
		for (int i = 0; i < colors->size(); i++)
		{
			const BColor& c = colors->at(i);
			text << c.r() << ',' << c.g() << ',' << c.b() << ',' << c.a() << ',' << '\n';
		}
		text -= ",\n";
	}
	else
	{
		for (int i = 0; i < colors->size(); i++)
		{
			const BColor& c = colors->at(i);
			text << c.r() << ',' << c.g() << ',' << c.b() << ',' << c.a() << ',';
		}
		text -= ',';
	}
	return true;
}
bool OscDocument::writeFaceArray(BSonNode* son, const BFaceArray* faces)
{
	son->setAttrib("size", faces->size());
	BString& text = (BString&)son->text();
	text.reset();

	SonFormat fmt(son->format());
	if (fmt.end_post == '\n')
	{
		for (int i = 0; i < faces->size(); i++)
		{
			const BFace& f = faces->at(i);
			text << f.a() << ',' << f.b() << ',' << f.c() << ',' << '\n';
		}
		text -= ",\n";
	}
	else
	{
		for (int i = 0; i < faces->size(); i++)
		{
			const BFace& f = faces->at(i);
			text << f.a() << ',' << f.b() << ',' << f.c() << ',';
		}
		text -= ',';
	}
	return true;
}
bool OscDocument::writeFloatTable(BSonNode* son, const BFloatTable& ftable)
{
	son->setAttrib("row", ftable.row());
	son->setAttrib("column", ftable.column());
	BString& text = (BString&)son->text();
	text.reset();

	SonFormat fmt(son->format());
	if (fmt.end_post == '\n')
	{
		for (int r = 0; r < ftable.row(); r++)
		{
			for (int c = 0; c < ftable.column(); c++)
			{
				text << ftable[r][c] << ',';
			}
			text << '\n';
		}
		text -= ",\n";
	}
	else
	{
		const float* data = ftable.data();
		for (int i = 0; i < ftable.size(); i++)
		{
			text << data[i] << ',';
		}
		text -= ',';
	}
	return true;
}
bool OscDocument::writeIndexArray(BSonNode* son, const BIndexArray* indices, int group)
{
	son->setAttrib("size", indices->size());
	BString& text = (BString&)son->text();
	text.reset();

	SonFormat fmt(son->format());
	if (fmt.end_post == '\n')
	{
		if (group == 0)
			group = indices->size();
		for (int i = 0; i < indices->size(); i += group)
		{
			for (int j = 0; j < group; j++)
			{
				text << indices->at(i + j) << ',';
			}
			text << '\n';
		}
		text -= ",\n";
	}
	else
	{
		for (int i = 0; i < indices->size(); i++)
		{
			text << indices->at(i) << ',';
		}
		text -= ',';
	}
	return true;
}
bool OscDocument::writePieceArray(BSonNode* son, const BPieceArray* pieces, int group)
{
	son->setAttrib("size", pieces->size());
	BString& text = (BString&)son->text();
	text.reset();

	SonFormat fmt(son->format());
	if (fmt.end_post == '\n')
	{
		if (group == 0)
			group = pieces->size();
		for (int i = 0; i < pieces->size(); i += group)
		{
			for (int j = 0; j < group; j++)
			{
				const BPiece& p = pieces->at(i + j);
				text << p.v() << ',' << p.vn() << ',' << p.vt() << ',';
			}
			text << '\n';
		}
		text -= ",\n";
	}
	else
	{
		for (int i = 0; i < pieces->size(); i++)
		{
			const BPiece& p = pieces->at(i);
			text << p.v() << ',' << p.vn() << ',' << p.vt() << ',';
		}
		text -= ',';
	}
	return true;
}
bool OscDocument::writeByteArray(BSonNode* son, const BByteArray* bytes, int group)
{
	son->setAttrib("size", bytes->size());
	BString& text = (BString&)son->text();
	text.reset();

	SonFormat fmt(son->format());
	if (fmt.end_post == '\n')
	{
		if (group == 0)
			group = bytes->size();
		for (int i = 0; i < bytes->size(); i += group)
		{
			for (int j = 0; j < group; j++)
			{
				text << bytes->at(i + j) << ',';
			}
			text << '\n';
		}
		text -= ",\n";
	}
	else
	{
		for (int i = 0; i < bytes->size(); i++)
		{
			text << bytes->at(i) << ',';
		}
		text -= ',';
	}
	return true;
}
